package com.jieao.template.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.util.IdUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jieao.template.common.util.CurrentlyLoggedInUtil;
import com.jieao.template.common.util.JsonUtils;
import com.jieao.template.entity.accountMgr.AccountDO;
import com.jieao.template.entity.accountMgr.AdminMenuVO;
import com.jieao.template.entity.accountMgr.AssociatedRoleDTO;
import com.jieao.template.entity.accountMgr.PasswordDTO;
import com.jieao.template.entity.pub.JsonData;
import com.jieao.template.entity.pub.Pagination;
import com.jieao.template.entity.roleMgr.AssignmentPermissionDTO;
import com.jieao.template.mapper.AccountMapper;
import com.jieao.template.service.AccountService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 账户表(Account)表服务实现类
 *
 * @author jzw
 * @since 2020-04-11 14:44:54
 */
@Service("accountService")
@Slf4j
public class AccountServiceImpl implements AccountService
{
    @Resource
    private AccountMapper accountMapper;

    /**
     * 个人中心--密码设置 修改当前登录人密码
     *
     * @param passwordDTO
     * @return com.northeastern.university.common.model.JsonData
     * @author Jzw
     * @date 2019/12/12 10:11
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonData setPassword(PasswordDTO passwordDTO)
    {
        //验证验证码
        String attribute = (String) SecurityUtils.getSubject().getSession().getAttribute("KAPTCHA_SESSION_KEY");
        if (!passwordDTO.getVerificationCode().equals(attribute))
        {
            return JsonData.fail("验证码不正确!");
        }
        String userId = CurrentlyLoggedInUtil.getUserId();
        AccountDO accountDO = accountMapper.queryById(userId);
        if (accountDO == null)
        {
            return JsonData.fail("服务器出现问题!请稍后再试!");
        }
        Md5Hash md5Hash = new Md5Hash(passwordDTO.getOldPassword(), accountDO.getSalt(), 2);
        if (accountDO.getEncryptedPassword().equalsIgnoreCase(md5Hash.toString()))
        {
            SecurityUtils.getSubject().getSession().removeAttribute("KAPTCHA_SESSION_KEY");
            accountDO.setEncryptedPassword(new Md5Hash(passwordDTO.getNewPassword(), accountDO.getSalt(), 2).toString());
            accountMapper.update(accountDO);
            return JsonData.ok();
        }
        else
        {
            return JsonData.fail("旧密码不正确!");
        }

    }

    /**
     * 获取验证码
     *
     * @param response@return void
     * @author Jzw
     * @date 2019/12/12 10:27
     */
    @Override
    public void getVerification(HttpServletResponse response)
    {
        //定义图形验证码的长、宽、验证码字符数、干扰元素个数
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
        try (ServletOutputStream outputStream = response.getOutputStream())
        {
            Cookie cookie = new Cookie("verificationCode", captcha.getCode());
            cookie.setPath("/");
            cookie.setMaxAge(3600);
            response.addCookie(cookie);
            //图形验证码写出，可以写出到文件，也可以写出到流
            captcha.write(response.getOutputStream());
            SecurityUtils.getSubject().getSession().removeAttribute("KAPTCHA_SESSION_KEY");
            SecurityUtils.getSubject().getSession().setAttribute("KAPTCHA_SESSION_KEY", captcha.getCode());
            response.getOutputStream().flush();
        } catch (IOException e)
        {
            log.error(e.getMessage());
        }

    }

    /**
     * 给用户分配权限
     *
     * @param assignmentPermissionDTO
     * @return void
     * @author Jzw
     * @date 2019/12/17 15:18
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignmentPermission(AssignmentPermissionDTO assignmentPermissionDTO)
    {
        List<String> checkList = assignmentPermissionDTO.getCheckList();
        List<String> halfList = assignmentPermissionDTO.getHalfList();
        String id = assignmentPermissionDTO.getId();
        //将半选和全选封装到一起
        List<Map<String, Object>> dataList = new LinkedList<>();
        checkList.forEach(ele -> {
            Map<String, Object> dataMap = new HashMap<>(3);
            dataMap.put("permissionId", ele);
            dataMap.put("userId", id);
            dataMap.put("checked", true);
            dataMap.put("id", IdUtil.simpleUUID());
            dataList.add(dataMap);
        });
        halfList.forEach(ele -> {
            Map<String, Object> dataMap = new HashMap<>(3);
            dataMap.put("permissionId", ele);
            dataMap.put("userId", id);
            dataMap.put("checked", false);//表示半选
            dataMap.put("id", IdUtil.simpleUUID());
            dataList.add(dataMap);
        });
        accountMapper.removeRolePermission(id);
        accountMapper.assignmentPermission(dataList);
    }

    /**
     * 获取当前用户已选的权限
     *
     * @param id accountId
     * @return java.util.List<java.lang.String>
     * @author Jzw
     * @date 2019/12/17 14:54
     */
    @Override
    public List<String> listCheckedPermission(String id)
    {
        return accountMapper.listCheckedPermission(id);
    }

    /**
     * 用户关联角色
     *
     * @param params
     * @return com.northeastern.university.common.model.JsonData
     * @author Jzw
     * @date 2019/12/19 15:41
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void associatedRole(AssociatedRoleDTO params)
    {
        accountMapper.removeAssociatedRole(params);
        params.setId(IdUtil.simpleUUID());
        accountMapper.associatedRole(params);
    }

    /**
     * 启禁用账户
     *
     * @param accountId 账户id
     * @return java.lang.Object
     * @author Jzw
     * @date 2019/12/13 13:49
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disOrEnaAccount(String accountId)
    {
        accountMapper.disOrEnaAccount(accountId);
    }

    /**
     * 获取 用户昵称 和 头像
     *
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @author Jzw
     * @date 2019/12/19 10:36
     */
    @Override
    public String getUserName()
    {
        return accountMapper.getUserName(CurrentlyLoggedInUtil.getUserId());
    }

    /**
     * 获取当前登录人菜单
     *
     * @return java.lang.Object
     * @author Jzw
     * @date 2019/12/19 16:24
     */
    @Override
    public List<AdminMenuVO> getMenuList()
    {
        return accountMapper.getMenuList(CurrentlyLoggedInUtil.getUserId());
    }

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public AccountDO queryById(String id)
    {
        return accountMapper.queryById(id);
    }

    /**
     * 通过用户名查询单条数据
     *
     * @param name 用户名
     * @return 实例对象
     */
    @Override
    @Transactional
    public AccountDO queryByName(String name)
    {
        return accountMapper.queryByName(name);
    }

    /**
     * 查询分页数据
     *
     * @param pagination 分页对戏
     * @return PageInfo 对象
     */
    @Override
    public PageInfo<AccountDO> queryAllByLimit(Pagination pagination)
    {
        PageHelper.startPage(pagination.getPageNum(),
                pagination.getPageSize());
        return new PageInfo<>(accountMapper.queryAllByLimit(JsonUtils.map2pojo(pagination.getParams(), AccountDO.class)));
    }

    /**
     * 查询全部数据
     *
     * @param account 筛选对象
     * @return 列表数据
     */
    @Override
    public List<AccountDO> queryAll(AccountDO account)
    {
        return accountMapper.queryAll(account);
    }

    /**
     * 新增数据
     *
     * @param account 实例对象
     * @return 实例对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountDO insert(AccountDO account)
    {
        account.setCreateId(CurrentlyLoggedInUtil.getUserId());
        String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
        Md5Hash md5Hash = new Md5Hash(account.getEncryptedPassword(), salt, 2);
        account.setEncryptedPassword(md5Hash.toString());
        account.setSalt(salt);
        account.setEnable(true);
        accountMapper.insert(account);
        return account;
    }

    /**
     * 修改数据
     *
     * @param account 实例对象
     * @return 实例对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(AccountDO account)
    {
        String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
        if (StringUtils.isNotBlank(account.getEncryptedPassword()))
        {
            Md5Hash md5Hash = new Md5Hash(account.getEncryptedPassword(), salt, 2);
            account.setEncryptedPassword(md5Hash.toString());
            account.setSalt(salt);
        }
        account.setUpdateId(CurrentlyLoggedInUtil.getUserId());
        return accountMapper.update(account);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteById(String id)
    {
        return accountMapper.deleteById(id) > 0;
    }

    /**
     * 通过主键集合批量删除数据
     *
     * @param idList 主键集合
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeletionByIdList(List<String> idList)
    {
        accountMapper.batchDeletionByIdList(idList);
    }
}